#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "YXConfig.h"
#include "YXLog.h"

#include "SDS.h"

static int yxLogLevel = DEFAULT_YX_LOG_LEVEL;

/**
 * 日志级别(int -> string)
 */
static char *yxLogLevelString[] = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL"};

/**
 * 日志级别颜色(int -> color)
 */
static char *yxLogLevelColor[] = {BLUE, GREEN, YELLOW, RED, MAGENTA};

__attribute__((constructor(YX_CONFIG_INIT_PRIORITY + 1))) static void yxLogInit() {
    char *level = yxConfig.getAndRemoveProperty("log.level");
    if (level != NULL) {
        setYXLogLevelByString(level);
        yxConfig.freeProperty(level);
    }
    log(YX_LOG_INFO, "YXLog initialized with level %s", getYXLogLevelString());
}

void setYXLogLevel(const int level) {
    if (level < YX_LOG_DEBUG || level > YX_LOG_FATAL) {
        throw("Invalid log level: %s", level);
    }
    yxLogLevel = level;
}

void setYXLogLevelByString(const char *level) {
    if (strcmp(level, "debug") == 0) {
        setYXLogLevel(YX_LOG_DEBUG);
    } else if (strcmp(level, "info") == 0) {
        setYXLogLevel(YX_LOG_INFO);
    } else if (strcmp(level, "warning") == 0) {
        setYXLogLevel(YX_LOG_WARNING);
    } else if (strcmp(level, "error") == 0) {
        setYXLogLevel(YX_LOG_ERROR);
    } else if (strcmp(level, "fatal") == 0) {
        setYXLogLevel(YX_LOG_FATAL);
    } else {
        throw("Invalid log level: %s", level);
    }
}

int getYXLogLevel() { return yxLogLevel; }

char *getYXLogLevelString() { return yxLogLevelString[yxLogLevel]; }

/**
 * 打印日志
 */
void _log(const char *currentFuntion, const int level, const char *text, ...) {
    // 获取当前时间
    time_t     now     = time(NULL);
    struct tm *tm_info = localtime(&now);

    // 打印日志级别和时间
    printf("[%s%s%s%s]  %s%02d-%02d-%02d %02d:%02d:%02d  %s%s%s %s: ", BOLD, yxLogLevelColor[level],
           yxLogLevelString[level], RESET, LIGHT_WHITE, tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
           tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, RESET, CYAN, currentFuntion, RESET);

    // 处理可变参数
    va_list args;
    va_start(args, text);
    vprintf(text, args);
    printf("\n");
    va_end(args);

    fflush(stdout);
}

/**
 * 抛出异常（会exit）
 */
void _throw(const char *file, const int line, const char *text, ...) {
    printf("%sException in %s:%d: ", RED, file, line);

    // 处理可变参数
    va_list args;
    va_start(args, text);
    vprintf(text, args);
    printf("%s\n", RESET);
    va_end(args);
    exit(1);
}
